package cn.kimmking.research.qedis.core.opr;

import cn.kimmking.research.qedis.core.AbstractOperator;

import java.util.*;
import java.util.stream.Stream;

/**
 * hash operators.
 *
 * @Author : kimmking(kimmking@apache.org)
 * @create 2024/6/11 下午8:04
 */
public class HashOperator extends AbstractOperator {

    public int hset(String key, String[] fields, String[] values) {
        if(fields == null || fields.length == 0) return 0;
        CacheEntry<?> entry = getOrInitCacheEntry(key);
        HashMap<String,String> exist = (HashMap<String, String>) entry.getValue();
        int index = 0;
        for(int i = 0; i < fields.length; i ++) {
            if(exist.put(fields[i], values[i]) == null) index ++;
        }
        return index;
    }

    public String hget(String key, String field) {
        if(checkInvalid(key)) return null;
        Map<String,String> v = (Map<String,String>) getEntryValue(key);;
        return v.get(field);
    }

    public String[] hgetall(String key) {
        if(checkInvalid(key)) return null;
        Map<String,String> v = (Map<String,String>)getEntryValue(key);
        return getMap().entrySet().stream()
                .flatMap(e -> Stream.of(e.getKey(),e.getValue())).toArray(String[]::new);
    }

    public String[] hmget(String key, String... fields) {
        if(checkInvalid(key)) return null;
        Map<String,String> v = (Map<String,String>) getEntryValue(key);
        return Arrays.stream(fields).flatMap(f -> Stream.of(f, v.get(f))).toArray(String[]::new);
    }

    public int hlen(String key) {
        if(checkInvalid(key)) return 0;
        Map<String,String> v = (Map<String,String>) getEntryValue(key);
        return v.size();
    }

    public int hexists(String key, String field) {
        if(checkInvalid(key)) return 0;
        Map<String,String> v = (Map<String,String>) getEntryValue(key);
        return v.containsKey(field) ? 1 : 0;
    }

    public int hdel(String key, String... fields) {
        if(checkInvalid(key)) return 0;
        Map<String,String> v = (Map<String,String>) getEntryValue(key);
        return (int) Arrays.stream(fields).map(v::remove).filter(Objects::nonNull).count();
    }

    private CacheEntry<?> getOrInitCacheEntry(String key) {
        CacheEntry<?> entry = getEntry(key);
        if(entry == null) {
            synchronized (getMap()) {
                if((entry = getEntry(key)) == null) {
                    entry = new CacheEntry<>(new HashMap<String,String>(16), System.currentTimeMillis(), -1000);
                    putEntry(key, entry);
                }
            }
        }
        return entry;
    }

}
